Skip to content

feat(capture): vertex service-account auth for vision captioning - #3362

Closed
WaterrrForever wants to merge 2 commits into
mainfrom
miao/capture-vertex-gemini
Closed

feat(capture): vertex service-account auth for vision captioning#3362
WaterrrForever wants to merge 2 commits into
mainfrom
miao/capture-vertex-gemini

Conversation

@WaterrrForever

Copy link
Copy Markdown
Collaborator

Why

The capture pipeline's vision captioning only accepts a Gemini API key (GEMINI_API_KEY/GOOGLE_API_KEY). Tenants whose Google access is service-account based — HeyGen's own workers included — can never turn it on: the Vertex endpoint rejects plain API keys, and the GCP key present in the worker env is not valid for the Gemini API. Observed effect: every capture's vision phase degrades with provider-error and asset-descriptions.md falls back to filename echoes, which downstream agents then compensate for by opening images one by one.

What

  • GOOGLE_GENAI_USE_VERTEXAI=true (the @google/genai SDK's own convention) routes captioning through Gemini on Vertex AI:
    • credentials from GOOGLE_SERVICE_ACCOUNT_INFO (inline SA JSON — the same variable HeyGen's multivendor Gemini provider already reads), else ADC
    • project falls back to the SA's project_id; location defaults to global (GOOGLE_CLOUD_PROJECT/GOOGLE_CLOUD_LOCATION override)
  • Provider priority: OPENROUTER_API_KEY → Vertex flag → GEMINI_API_KEY. The flag outranks a bare key because a tenant that sets it is saying its key material is Vertex-side.
  • Vertex default model is gemini-2.5-flash-lite (Vertex does not publish the gemini-3.1-flash-lite-preview name the API-key path defaults to; verified 404 vs 200). HYPERFRAMES_GEMINI_MODEL still overrides.
  • asset-descriptions.md header now reflects the Vertex option.

Testing

  • vitest run src/capture/contentExtractor.test.ts — 18 passed (5 new: config resolution × 4, provider selection through the mocked SDK asserting the Vertex default model).
  • tsc --noEmit — no errors in the touched files.
  • Real capture of anthropic.com with GOOGLE_GENAI_USE_VERTEXAI=true + the existing worker SA: vision phase completed, 3 images captioned with Vertex Gemini, captions are genuine content descriptions (og-image: "A black text logo, ANTHROPIC, is centered on a light background"), 32 SVGs rasterized+captioned.

🤖 Generated with Claude Code

WaterrrForever and others added 2 commits August 20, 2026 17:22
The Vertex Gemini endpoint rejects plain API keys, so tenants whose Google access
is service-account based could never enable vision captioning: the vision phase
degraded with provider-error and asset-descriptions.md fell back to filename echoes.

Opt in with GOOGLE_GENAI_USE_VERTEXAI=true (the @google/genai SDK convention).
Credentials come from GOOGLE_SERVICE_ACCOUNT_INFO as inline SA JSON when set, else
ADC; project falls back to the SA's own project_id and location defaults to global.
The flag outranks a bare GEMINI_API_KEY because a tenant that sets it is saying its
key material is Vertex-side; OPENROUTER_API_KEY stays the top-priority opt-in.
Vertex default model is gemini-2.5-flash-lite — Vertex does not publish the 3.x
flash-lite preview name the Gemini API path defaults to.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vertex serves the GA gemini-3.1-flash-lite name (the -preview alias is
Gemini-API-only), so the Vertex path can default to the same tier as the
API-key path instead of stepping down to 2.5. Verified multimodal 200 on
the worker service account.
@WaterrrForever
WaterrrForever force-pushed the miao/capture-vertex-gemini branch from 0c1c259 to 80b536d Compare August 20, 2026 09:29

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 80b536d21b2b2ba17f34ea45ac05bc54395b5757. All required checks are green; BLOCKED is only the reviewer gate.

Strengths

  • packages/cli/src/capture/contentExtractor.ts:308-331 keeps provider precedence explicit and uses a Vertex-valid default model.
  • The service-account JSON path is isolated and covered with focused configuration/provider tests.

Blocking issue

  • blocker — packages/cli/src/capture/contentExtractor.ts:247-266,387-395: the documented ADC fallback can return { project: undefined, location: "global" }, which is then passed to new GoogleGenAI({ vertexai: true, ... }). In the pinned @google/genai client, Vertex auth is considered sufficient only when both project+location (or an API key/custom base URL) exist; ADC credentials alone do not supply the missing project at this constructor boundary, so it throws Authentication is not set up before captioning. GOOGLE_GENAI_USE_VERTEXAI=true with ADC and no explicit project therefore degrades to internal-error, contradicting the advertised fallback. Resolve the ADC project ID before constructing the client, or reject this configuration explicitly with an actionable outcome, and add the no-project ADC regression.

The PR body also still names gemini-2.5-flash-lite, while this exact head correctly uses gemini-3.1-flash-lite; please update the description when fixing the blocker.

Verdict: REQUEST CHANGES
Reasoning: the new ADC-only configuration path cannot initialize the pinned Vertex client unless the caller also supplies an explicit project, so a stated primary use case fails before its first request.

— Magi

@WaterrrForever

Copy link
Copy Markdown
Collaborator Author

Closing — superseded by #3561, which is a functional superset of this change across the same three files.

Worth recording what #3561 changes beyond this PR, since it is not a pure extension: it swaps the credential contract. This PR used GOOGLE_SERVICE_ACCOUNT_INFO plus ADC; #3561 uses HYPERFRAMES_VERTEX_PROJECT_ID + HYPERFRAMES_VERTEX_SERVICE_ACCOUNT. Nothing on the experiment-framework side sets the new names today — heygen-com/experiment-framework#48887 is what bridges it. So #3561 alone changes nothing in production, and the merge order matters.

Confirmed independently by Rames and Magi in review of #3561.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants